﻿/// <reference name="MicrosoftAjax.js"/>

/*
MapControl2 ajax client-side map control. The server side counterpart of this client control
is LOAMap.cs. Please refer to that file for a description of server fields that are passed
down to the client once the control is instantiated. Please refer also to google maps 
api documentation (http://code.google.com/apis/maps/documentation/reference.html) for details
about the various google classes that are used within the control.
*/

// Loads the google maps api and registers a namespace for this client control.
google.load("maps", "2.x");
Type.registerNamespace("MapControl2");

/*
Array that contain all the strings used in the map control, to use if you wantt change language in the map control.
*/
var mapStrings=new Array ();
mapStrings["add_destination"]='Add destination';
mapStrings["remove_trip"]='Remove trip';
mapStrings["select_vehicle"]="Select vehicle >>";
mapStrings["insert_waypoint"]='Insert waypoint';
mapStrings["take_in_passenger"]='Take in passenger';
mapStrings["take_off_passenger"]='Take off passenger';
mapStrings["detach_passenger"]='Detach passenger';
mapStrings["detach_from_trip"]='Detach from trip';
mapStrings["language_istructions"]="en_US";

mapStrings["passengers_in"] = "N. Passenger in";    // label in marker info tab
mapStrings["passengers_off"] = "N. Passenger out";    // label in marker info tab

mapStrings["start_info_route"]='Start';
mapStrings["startDescr_info_route"]='Start description';
mapStrings["end_info_route"]='End';
mapStrings["endDescr_info_route"]='End description';
mapStrings["dist_info_route"]='Distance';
mapStrings["time_info_route"]='Time';
mapStrings["wayNumb_info_route"]='Waypoints number';
mapStrings["title_info_route"]='Route Details';


mapStrings["start_info_trip"]='Trip start';
mapStrings["startDescr_info_trip"]='Start description';
mapStrings["end_info_trip"]='Trip end';
mapStrings["endDescr_info_trip"]='End description';
mapStrings["dist_info_trip"]='Covered distance';
mapStrings["time_info_trip"]='Spent Time';
mapStrings["routeN_info_trip"]='Routes number';
mapStrings["title_info_trip"]='Trip Details';

mapStrings["endLabel_trip"]='Trip End';
mapStrings["end_trip"]='End';
mapStrings["endDescr_trip"]='End description';


mapStrings["waypointLabel"]= 'Waypoint';
mapStrings["waypoint_Location"]='Location';
mapStrings["waypoint_Descr"]='Description';
/* 
Client-control constructor. It defines the fields that will be filled by the Microsoft Ajax
framework at control instantiation.
*/
MapControl2.LOAMap = function(element) {
    MapControl2.LOAMap.initializeBase(this, [element]);
    
    this._mapDiv = null;            // map div id
    this._cmdToEval = new Array();  // a set of javascript commands that must be evaluated 
                                    // at control initialization (sent by the server)
    
    this._map = null;               // GMap2 object
    this._tripsManager = null;      // the AAATripManager object that manages the trip creation process
    this._formatter = null;         // a visitor that formats the content of the visible markers on the map
    
    // some references to aspx page controls linked to this map control
    this._stuff = new Object({'vehicleCbo':null, 'depBox':null, 'arrBox':null});
    this._stuff.passengerHandler = null;
}

MapControl2.LOAMap.prototype = {

    // ---------------- initialization and dispose ----------------------------------------------------------
    initialize: function() {
        MapControl2.LOAMap.callBaseMethod(this, 'initialize');
        if (document[this.get_id()] == null)
        {
            // creates the GMap2 object and other linked objects
            if (GBrowserIsCompatible())
            {
                this._map = new MapControl2.AAAMap($get(this._mapDiv));
                this._map.addControl(new google.maps.LargeMapControl());    // some predefined google controls
                this._map.addControl(new google.maps.OverviewMapControl()); // are added
                this._map.addControl(new google.maps.MenuMapTypeControl());

                this._map.enableDoubleClickZoom();
                //this._map.disableDoubleClickZoom();

                this._map.setCenter(new google.maps.LatLng(parseFloat(43.7212418), parseFloat(10.4075288))); 
                this._map._myCtrl = this;
                
                // here we create the formatter visitor and the AAATripsManager instance
                var vf = new MapControl2.AAAVisitorFactory();
                this._formatter = vf.createVisitor
                    (MapControl2.AAAVisitorFactory.MARKERS_FORMATTER_VISITOR);
                this._tripsManager = new MapControl2.AAATripsManager(this._map);
                google.maps.Event.bind(this._map, 'maperror', this, this._onMapError);
                
                // saves some objects into the dom
                document[this.get_id()] = new Object();
                document[this.get_id()].map = this._map;
                document[this.get_id()].tripsManager = this._tripsManager;
                document[this.get_id()].formatter = this._formatter;
                document[this.get_id()].stuff = this._stuff;
            }            
        }else
        {
            // To mantain the map control state, we save the state to the DOM when the control
            // is instantiated, and then we restore the state from the DOM. This operation is
            // necessary because the map control resides in an update panel. 
            this._map = document[this.get_id()].map;
            this._tripsManager = document[this.get_id()].tripsManager;
            this._formatter = document[this.get_id()].formatter;
            this._stuff = document[this.get_id()].stuff;
        }
        
        // now that we have our map control, we can execute server operations
        this._setupMapFromServer();               
    },
    dispose: function() {        
        MapControl2.LOAMap.callBaseMethod(this, 'dispose');
    },
    
    // Performs actions sent by the server. The commands to be execute resides in the _cmdToEval array.
    _setupMapFromServer: function()
    {
        for(var i=0; i<this._cmdToEval.length; i++)
            eval(this._cmdToEval[i]);
        
        this.checkTargetControlIDs();        
    },
    
    checkTargetControlIDs: function()
    {
        // Appendo la sincronizzazione all'onclick dei controlli target
        // siamo di ritorno dal server, bisogna aggiornare la onclick dei controlli target
        // questi possono esser in un update panel e quindi essere ricalcolati, quindi va eseguita sempre
        if(this._map._targetControlIDs != null)
        {   
            var thisId = this.get_id();
            var ids = this._map._targetControlIDs.split(";");
            for(var j=0; j<ids.length; j++)
            { 
                var element = document.getElementById(ids[j]);
                var senderID = ids[j];
                if(element!=null)
                {
                    if(element["__hasSincronize"+thisId] != null) 
                        continue;
                        
                    if(element.onclick != null) // diverso da null vuol dire che è true...
                    {   
                        var oldOnClick = element.onclick;
                        
                        // Si memorizza un flag per sapere se la sincronize è già stata inserita, perchè il controllo
                        // target potrebbe non essere in un update panel e quindi avere già inserita la sincronize
                        element.onclick = function(event){
                                                            if( !SincronizeLOAMapControl(thisId, senderID, event) ) 
                                                                return false;
                                                            
                                                            oldOnClick(event);
                                                            _oldEvent = null;
                                                            _oldSender = null;    
                                                          };
                    }
                    else
                    {
                        element.onclick = function(event){ if( !SincronizeLOAMapControl(thisId, senderID, event) ) return false;};
                    }
                    
                    // Si memorizza un flag per sapere se la sincronize è già stata inserita, perchè il controllo
                    // target potrebbe non essere in un update panel e quindi avere già inserita la sincronize
                    element["__hasSincronize"+thisId] = true;
                }// if(element!=null)
            }// for(var j=0; j<ids.length; j++)
        }//if(this._map._targetControlIDs != null)         
    },
    
    
    // MapControl2 exposed properties
    get__cmdToEval: function()
    {
        return this._cmdToEval;
    },
    set__cmdToEval: function(value)
    {
        for(var i=0; i<value.length; i++)
            this._cmdToEval.push(value[i]);
    },
    setVehicleCbo: function(cbo){
        this._stuff.vehicleCbo = cbo;
    },
    setDepBox: function(box){
        this._stuff.depBox = box;        
    },
    setArrBox: function(box){
        this._stuff.arrBox = box;        
    },
    // -----------------------------------------------------------------------------------------------
    
    // ----------------- public methods --------------------------------------------------------------
    
    setHelp: function(infoString)
    {
        SetHelp(this._map,infoString)
    },
    
    // Retrieves the trip with given id from the server and shows it on the map.
    addTripByID: function(id)
    {
        // delegates the AAATripManager instance to create the trip and passes a 
        // callback function to be invoked when the trip is properly created.
        this._tripsManager.createTripByID(id, false, 
             Function.createDelegate(this, this._onCreateTripCallback));
    },
    
    /* 
    Creates a new trip. 
    routes --> bidimensional array of strings that identify the various routes of the trip.
    routes[i] identifies the locations that make up the i-th route (e.g. "Firenze", "Pisa", "Livorno").
    vehicle --> info about the vehicle used for the trip. A vehicle object has three fields: Id, 
    that identifies the user's vehicle (number); Class: vehicle class (bike, car, airplane...); 
    Type: vehicle description ("Fiat Punto", "Ford Fiesta"...)
    */
    addTripByRoutes: function(routes, vehicle)
    {
        if(this._map._editableTrip != null)
            this._map._editableTrip.clear();
        
        this._tripsManager.createTrip
            (routes, Function.createDelegate(this, this._onCreateTripCallback), vehicle);
    },
    
    // Creates a route from <a> to <b> with vehicle <vehicle>. <a> and <b> are location strings, while
    // <vehicle> is a vehicle object. Please refer to addTripByRoutes for vehicle object description.
    setEditableTripA2B: function(a, b, vehicle)
    {   
        var route = new Array(a, b);
        var routes = new Array(route);
        this.addTripByRoutes(routes, vehicle);
    },
    
    // Creates a trip from a geoloc array and a vehicle object. The array defines the various stages
    // of the trip; for example, if the array is ["Pisa", "Livorno", Firenze], then we create a trip
    // which starts from Pisa and ends in Firenze. Livorno is a stage between Pisa and Firenze.
    setEditableTripA2BFromGeolocs: function(geolocs, vehicle){
        if(this._map._editableTrip != null)
            this._map._editableTrip.clear();
        
        this._tripsManager.createTripFromGeolocs
            (geolocs, Function.createDelegate(this, this._onCreateTripCallback), vehicle);
    },
    
    // Looks for a registered vehicle object with the given id and, if present, returns it.
    // If the vehicle is not found, a default vehicle object is returned (a car vehicle).
    getVehicleById: function(id)
    {
        var vehicle = null;
        for(var i=0; i<this._map._listVehicles.length; i++)
            if(this._map._listVehicles[i].Id == id)
            {
                vehicle = this._map._listVehicles[i];
                break;
            }
        if(vehicle == null)
        {
            vehicle = new Object();
            vehicle.Id = -1;
            vehicle.Class = 0; //car
            vehicle.Type = "Unknown";
        }
        return vehicle;
    },
    
    // Returns the json serialization of the current editable trip.
    getJsonTrip: function()
    {
        var selected_trip = this._map.getEditableTrip();
        
        // the serialization is done by visiting the trip structure with the json serializer visitor
        if (selected_trip !== null)
        {
            var vf = new MapControl2.AAAVisitorFactory();
            var jsonSerializerVisitor = vf.createVisitor(MapControl2.AAAVisitorFactory.JSON_SERIALIZER_VISITOR);
            selected_trip.accept(jsonSerializerVisitor);
            return (jsonSerializerVisitor.getResult());
        }
        return "{}";
    },
    
    // Returns the json serialization of the passengers markers.
    getPassengerLocs: function()
    {
        if(this._map._passengerDep == null) 
            return "";
        
        var vf = new MapControl2.AAAVisitorFactory();
        var jsonSerializerVisitor = vf.createVisitor(MapControl2.AAAVisitorFactory.JSON_SERIALIZER_VISITOR);
            
        return  jsonSerializerVisitor._serializeGeoLoc(this._map._passengerDep._geoloc) + "\n"+
                this._map._passengerDep._radiusKm + "\n"+
                jsonSerializerVisitor._serializeGeoLoc(this._map._passengerArr._geoloc) + "\n"+
                this._map._passengerArr._radiusKm;        
    },
    
    getStartGeoloc: function()
    {
        if(this._map._editableTrip == null) 
            return null;
        else
        {
            var routes = this._map._editableTrip._routes;
            var firstRouteModel = routes[0]._routeModel;
            return firstRouteModel.start;
        }
    },
    
    getEndGeoloc: function()
    {
        if(this._map._editableTrip == null) 
            return null;
        else
        {
            var routes = this._map._editableTrip._routes;
            var lastRouteModel = routes[routes.length-1]._routeModel;
            return lastRouteModel.end;
        }
    },
    
    
    // Returns a reference to the GMap2 object used in this map control.
    getGMap: function(){
        return this._map;
    },
    
    transformToEditableMap: function()
    {
        var map = this._map;
        if(map.isEditable()) return;
        
        var jsonTrip = null;
        if(map._trips.length != 0)
        {
            var vf = new MapControl2.AAAVisitorFactory();
            var jsonSerializerVisitor = vf.createVisitor(MapControl2.AAAVisitorFactory.JSON_SERIALIZER_VISITOR);
            map._trips[0].accept(jsonSerializerVisitor);
            jsonTrip = jsonSerializerVisitor.getResult();
        }
        map.setEditable(true);
        map.clearUneditableTrips();
        this._tripsManager.createTripByJson( jsonTrip, true, Function.createDelegate(this, this._onCreateTripCallback));
    },
    
    transformToUneditableMap: function()
    {
        if(!this._map.isEditable()) return;
        
        var jsonTrip = null;
        if(this._map._editableTrip != null)
        {
            var vf = new MapControl2.AAAVisitorFactory();
            var jsonSerializerVisitor = vf.createVisitor(MapControl2.AAAVisitorFactory.JSON_SERIALIZER_VISITOR);
            this._map._editableTrip.accept(jsonSerializerVisitor);
            jsonTrip = jsonSerializerVisitor.getResult();
        }
        this._map.setEditable(false);
        this._map.clearUneditableTrips();
        this._map.clearEditableTrip();
        
        if(jsonTrip != null)
            this._tripsManager.createTripByJson(jsonTrip, false, Function.createDelegate(this, this._onCreateTripCallback));
    },
    
    // -------------------------------------------------------------------------------------------------------
    
    // -------------------------- event handlers -------------------------------------------------------------
    // Callback invoked when a new trip has been created. aaaTrip is the instance of AAATrip that
    // has been created.
    _onCreateTripCallback: function(aaaTrip)
    {
        if(aaaTrip.isEditable())
            this._map.setEditableTrip(aaaTrip);
        else
            this._map.addTrip(aaaTrip);                
        
        // registers some handlers with this trip
        google.maps.Event.bind(this._map, 'tripchange', this, this._onTripChange);
        google.maps.Event.bind(this._map, 'triperror', this, this._onTripError);
        aaaTrip.accept(this._formatter);
        google.maps.Event.trigger(this._map, 'tripload', aaaTrip);
    },
    
    // trip change event handler
    _onTripChange: function(aaaTrip)
    {        
        // reformats the trip markers
        aaaTrip.accept(this._formatter);        
    },
    
    // trip error event handler
    _onTripError: function(aaaTrip, aaaRoute, error)
    {
        if (error.type == 'loa_error') alert(error.err.get_message());
        google.maps.Event.trigger(this._map, 'triperror', this, aaaTrip, aaaRoute, error);
    },
    
    // map error event handler
    _onMapError: function(err)
    {
        alert(err.err.get_message());
        google.maps.Event.trigger(this, 'maperror', this, this._map, err);
    }
    // -------------------------------------------------------------------------------------------------------
}
MapControl2.LOAMap.registerClass('MapControl2.LOAMap', Sys.UI.Control);


// Funzione che permette di aggiornare lo stato del viaggio editato lato client
// sul server. E' stata pensata per essere inserita nell'onclick di un controllo
// target in modo da automatizare l'update per l'utente che usa il controllo
// @param controlID id del controllo mappa
// @param senderID id del controllo target

var _oldTexButton;
var _oldSender, _oldEvent;

function SincronizeLOAMapControl(controlID, senderID, event)
{
   var mapControl = Sys.Application.findComponent(controlID);
   var aaamap = mapControl._map;
   var ok = true;
   
    if(aaamap.isEditable())
    {
        // server need edited trip
        var empty = false;
        var trip = aaamap.getEditableTrip();
        var routes = null;
        if(trip != null)
        {
            var routes = trip.getRoutes();
            empty = routes.length == 0;
        }
        else
            empty = true;
            
        if(empty)
        {
           alert('Empty trip!');
           _restoreBtnVal(senderID);
           return false;
        }
        else
        { 
            switch( trip.getStatus() )
            {
                case AAASTATUS_ERROR:   
                    alert('Invalid trip!');
                    _restoreBtnVal(senderID);
                    return false;
            
                case AAASTATUS_LOADING:
                    
                    // TO DO: vedere di attendere la terminazione del loading del trip
                    if(senderID != null && false)
                    {
                        var btn = document.getElementById(senderID);
                        if(btn != null)
                        {
                            if(_oldTexButton==null )
                                _oldTexButton = btn.value;
                            btn.value = 'Waiting...'
                        }
                        _oldSender = btn;
                        _oldEvent = event;
                        setTimeout("recallSynchronize();", 500);                        
                    }
                    else
                        alert("Trip is loading... wait a second!");
                        
                    return false;
            }
            
            // sono state scorse tutte le tratte del viaggio e sono ok... si va sul server
            var controlHF_et = document.getElementById('__'+controlID+'_HF_EDITABLE');
            
            // prendere serializzazione del viaggio editabile
            controlHF_et.value = mapControl.getJsonTrip();
            _restoreBtnVal(senderID);
        }
    }
    
    // server new passenger locations, if exist
    var controlHF_pl = document.getElementById('__'+controlID+'_HF_PASSENGER');
    controlHF_pl.value = mapControl.getPassengerLocs();
   
    return true;
}

function recallSynchronize()
{
    if(_oldSender != null && _oldEvent != null)
    {
        _oldSender.onclick();
        //_oldSender.dispatchEvent(_oldEvent);    
    }
}


function _restoreBtnVal(btnID){
   if(_oldTexButton != null){
       var btn = document.getElementById(btnID);
       if(btn != null)
            btn.value = _oldTexButton;
       _oldTexButton = null;
   }
}

// some useful constants
MapControl2.NAVIGATOR_IS_IE = (navigator.appVersion.indexOf("MSIE") != -1);
MapControl2.AAAMAP_ELEMENT = 0;
MapControl2.AAATRIP_ELEMENT = 1;
MapControl2.AAAROUTE_ELEMENT = 2;

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();